package cn.edu.cug.cs.gtl.renders.openinventor.utils;


import cn.edu.cug.cs.gtl.apis.render.callbacks.SelectionPathCallback;
import cn.edu.cug.cs.gtl.common.Pair;
import cn.edu.cug.cs.gtl.protos.*;
import cn.edu.cug.cs.gtl.apis.render.Render;
import cn.edu.cug.cs.gtl.renders.openinventor.callbacks.MyDeselectionPathCallback;
import cn.edu.cug.cs.gtl.renders.openinventor.callbacks.MySelectionPathCallback;
import cn.edu.cug.cs.gtl.renders.openinventor.callbacks.SelectionPathCallbackImpl;
import com.google.protobuf.InvalidProtocolBufferException;
import com.openinventor.inventor.*;
import com.openinventor.inventor.misc.callbacks.SoSelectionPathCB;
import com.openinventor.inventor.nodes.*;
import com.openinventor.ldm.nodes.SoTransferFunction;
import com.openinventor.volumeviz.nodes.SoVolumeData;
import com.openinventor.volumeviz.nodes.SoVolumeRender;

import java.awt.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.DoubleBuffer;
import java.util.ArrayList;
import java.util.List;

import static com.openinventor.inventor.nodes.SoIndexedFaceSet.SO_END_FACE_INDEX;
import static com.openinventor.inventor.nodes.SoIndexedLineSet.SO_END_LINE_INDEX;

public class RenderUtils {

    /**
     * 根据节点名称在指定的场景图中查询节点
     * @param sceneGraph 场景图节点
     * @param parent  sceneGraph节点的父节点
     * @param nodeName 待查找的节点的名称
     * @param result 返回节点及其父节点
     */
    protected static void findNode(SoNode sceneGraph, SoNode parent, String nodeName, Pair<SoNode,SoNode> result){
        if(sceneGraph == null )
            return;
        if(sceneGraph.getName().equals(nodeName)) {
            result.setKey(sceneGraph);
            result.setValue(parent);
        }
        else{
            if(sceneGraph instanceof  SoGroup){
                int c = ((SoGroup) sceneGraph).getNumChildren();
                for(int i=0;i<c;++i) {
                    if((((SoGroup) sceneGraph).getChild(i).equals(nodeName))){
                        result.setKey(((SoGroup) sceneGraph).getChild(i));
                        result.setValue(sceneGraph);
                        return;
                    }
                }
                for(int i=0;i<c;++i) {
                    findNode(((SoGroup) sceneGraph).getChild(i),sceneGraph,nodeName,result);
                }
            }
        }
    }

    public static Pair<SoNode,SoNode> findNode(SoNode sceneGraph, Project project){
        Pair<SoNode,SoNode> p = new Pair<>();
        String nodeName = nodeName(project);
        findNode(sceneGraph,null,nodeName,p);
        return p;
    }

    public static Pair<SoNode,SoNode> findNode(SoNode sceneGraph, Map map){
        Pair<SoNode,SoNode> p = new Pair<>();
        String nodeName = nodeName(map);
        findNode(sceneGraph,null,nodeName,p);
        return p;
    }

    public static Pair<SoNode,SoNode> findNode(SoNode sceneGraph, Layer layer){
        Pair<SoNode,SoNode> p = new Pair<>();
        String nodeName = nodeName(layer);
        findNode(sceneGraph,null,nodeName,p);
        return p;
    }

    public static SoNode removeNode(SoNode sceneGraph, Project project){
        SoSeparator root = (SoSeparator) sceneGraph;
        return root;
    }

    public static SoNode removeNode(SoNode sceneGraph, Map map){
        Pair<SoNode,SoNode> p =  findNode(sceneGraph,map);
        if(p!=null){
            if(p.getFirst()!=null){
                if(p.getSecond()!=null) {
                    SoGroup g = (SoGroup)p.getSecond();
                    g.removeChild(p.getFirst());
                    return p.getFirst();
                }
            }
        }
        return null;
    }

    public static SoNode removeNode(SoNode sceneGraph, Layer layer){
        Pair<SoNode,SoNode> p =  findNode(sceneGraph,layer);
        if(p!=null){
            if(p.getFirst()!=null){
                if(p.getSecond()!=null) {
                    SoGroup g = (SoGroup)p.getSecond();
                    g.removeChild(p.getFirst());
                    return p.getFirst();
                }
            }
        }
        return null;
    }
    public static String nodeName(Project project){
        return Render.nodeName(project);
    }
    public static String nodeName(Map map){
        return Render.nodeName(map);
    }
    public static String nodeName(Layer layer){
        return Render.nodeName(layer);
    }
    public static String nodeName(Geometry geometry){
        return Render.nodeName(geometry);
    }


    static Geometry findGeometryByNodeName(String s, Project project){
        return null;

    }

    static Layer findLayerByNodeName(String s, Project project){
        return null;

    }

    static Map findMapByNodeName(String s, Project project){
        return null;

    }


    public static SoNode createProjectNode(Project project) throws InvalidProtocolBufferException {
        //SoSelection selectionRootNode= new SoSelection();
        SoSeparator root = new SoSeparator();

        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(project));
        int mapSize = project.getMapCount();
        for(int i=0;i<mapSize;++i){
            SoNode soNode = createMapNode(project.getMap(i));
            if(soNode!=null)
                root.addChild(soNode);
        }
        return root;

    }

    public static SoNode createMapNode(Map map) throws InvalidProtocolBufferException {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(map));
        int layerSize = map.getLayerCount();
        for(int i=0;i<layerSize;++i){
            SoNode soNode = createLayerNode(map.getLayer(i));
            if(soNode!=null)
                root.addChild(soNode);
        }
        return root;
    }

    public static SoNode createLayerNode(Layer layer) throws InvalidProtocolBufferException {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(layer));
        int geometrySize = layer.getGeometryCount();
        for(int i=0;i<geometrySize;++i){
            SoNode soNode = createGeometryNode(layer.getGeometry(i));
            if(soNode!=null)
                root.addChild(soNode);
        }
        return root;
    }

    public static SoNode createGeometryNode(Geometry geometry) throws InvalidProtocolBufferException {
        GeometryType geometryType = geometry.getType();

        switch (geometryType) {
            case POINT3D: {
                Point3D shape = geometry.getShape().unpack(Point3D.class);
                return createPoint3DNode(geometry,shape) ;
            }
            case LINESTRING3D: {
                LineString3D shape = geometry.getShape().unpack(LineString3D.class);
                return createLineString3DNode(geometry,shape) ;
            }
            case POLYLINE3D: {
                Polyline3D shape = geometry.getShape().unpack(Polyline3D.class);
                int i = 0;
                return createPolyline3DNode(geometry,shape) ;
            }
            case POLYGONALMESH3D: {
                PolygonalMesh3D shape = geometry.getShape().unpack(PolygonalMesh3D.class);
                return createPolygonalMesh3DNode(geometry,shape);
            }
            case POLYHEDRALMESH3D: {
                PolyhedralMesh3D shape = geometry.getShape().unpack(PolyhedralMesh3D.class);
                return createPolyhedralMesh3D(geometry,shape) ;
            }
            case VOXEL_MODEL:{
                VoxelModel shape = geometry.getShape().unpack(VoxelModel.class);
                return createVoxelModelNode(geometry,shape);
            }
            case VOLUME_MODEL:{
                VolumeModel shape = geometry.getShape().unpack(VolumeModel.class);
                return createVoxelVolumeNode(geometry,shape);
            }
            default: {
                System.out.println("不支持的几何类型");
                return null;
            }
        }
    }

    /*
                                            SoSeparator
                                             |
                   |-------------------|----------------|---------------------|
                  SoDrawStyle     SoMaterial      SoCoordinate3       SoIndexedPointSet
     */
    protected static SoNode createPoint3DNode(Geometry geometry,Point3D point3D){
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));

        //material
        {
            List<Color4f> color4fs= null;//polyline3D.getColorList();
            if(color4fs!=null && color4fs.isEmpty()==false) {
                int size = color4fs.size();
                SbColor[] sbColors=new SbColor[size];
                float [] rgba=new float[3];
                for(int i=0;i<size;++i){
                    rgba[0] = color4fs.get(i).getR();
                    rgba[1] = color4fs.get(i).getG();
                    rgba[2] = color4fs.get(i).getB();
                    //rgba[3] = color4fs.get(i).getA();
                    sbColors[i]=new SbColor(rgba);
                }
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.PER_VERTEX_INDEXED);
            }
            else{
                Color4f color4f = geometry.getColor();
                SbColor[] sbColors=new SbColor[1];
                sbColors[0]=new SbColor(color4f.getR(),color4f.getG(),color4f.getB());
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.OVERALL);
            }

        }
        //coordinates
        {
            SoCoordinate3 coordinate3 = new SoCoordinate3();
            int vertexCount = 1;
            SbVec3d[] vec3ds = new SbVec3d[vertexCount];
            vec3ds[0] = new SbVec3d(point3D.getLocation().getX(),point3D.getLocation().getY(),point3D.getLocation().getZ());
            coordinate3.point.setValues(0, vec3ds);
            root.addChild(coordinate3);
        }
        {
            //indexes
            int vertexCount =1;
            int [] idxes= new int[vertexCount+1];
            int i=0;
            for(i=0;i<vertexCount;++i){
                idxes[i]=i;
            }
            //idxes[i]=SO_END_POINT_SET_INDEX;
            SoIndexedPointSet lineSet = new SoIndexedPointSet();
            lineSet.coordIndex.setValues(0,idxes);
            root.addChild(lineSet);

            SoCube soCube = new SoCube();
            soCube.width.setValue(0.1f);
            SoTranslation soTranslation = new SoTranslation();
            soTranslation.translation.setValue(
                    Double.valueOf(point3D.getLocation().getX()).floatValue(),
                    Double.valueOf(point3D.getLocation().getY()).floatValue(),
                    Double.valueOf(point3D.getLocation().getZ()).floatValue());
            SoScale soScale = new SoScale();
            soScale.scaleFactor.setValue(0.001f,0.001f,0.001f);
            root.addChild(soTranslation);
            root.addChild(soScale);
            root.addChild(soCube);
        }
        return root;
    }



    /*
                                                SoSeparator
                                             |
                   |-------------------|----------------|---------------------|
                  SoDrawStyle     SoMaterial      SoCoordinate3       SoIndexedLineSet
     */
    protected static SoNode createPolyline3DNode(Geometry geometry,Polyline3D polyline3D){
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));
        //material
        {
            List<Color4f> color4fs= polyline3D.getColorList();
            if(color4fs!=null && color4fs.isEmpty()==false) {
                int size = color4fs.size();
                SbColor[] sbColors=new SbColor[size];
                float [] rgba=new float[3];
                for(int i=0;i<size;++i){
                    rgba[0] = color4fs.get(i).getR();
                    rgba[1] = color4fs.get(i).getG();
                    rgba[2] = color4fs.get(i).getB();
                    //rgba[3] = color4fs.get(i).getA();
                    sbColors[i]=new SbColor(rgba);
                }
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.PER_VERTEX_INDEXED);
            }
            else{
                Color4f color4f = geometry.getColor();
                SbColor[] sbColors=new SbColor[1];
                sbColors[0]=new SbColor(color4f.getR(),color4f.getG(),color4f.getB());
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.OVERALL);
            }

        }
        //coordinates
        {
            SoCoordinate3 coordinate3 = new SoCoordinate3();
            int vertexCount = polyline3D.getVertexCount();
            SbVec3d[] vec3ds = new SbVec3d[vertexCount];
            int i = 0;
            for (Vertex3d v : polyline3D.getVertexList()) {
                vec3ds[i] = new SbVec3d(v.getX(), v.getY(), v.getZ());
                ++i;
            }
            coordinate3.point.setValues(0, vec3ds);
            root.addChild(coordinate3);
        }
        {
            //indexes
            ArrayList<Integer> idx = new ArrayList<>();
            List<Integer> list = polyline3D.getIndexList();
            int i=0;
            if(list.isEmpty()==false){
                int lineSize  = list.get(i);
                ++i;
                for(int k=0;k<lineSize;++k) {
                    int vertexSize = list.get(i);
                    ++i;
                    for(int j=0;j<vertexSize;++j){
                        idx.add(list.get(i));
                        ++i;
                    }
                    idx.add(SO_END_LINE_INDEX);
                }
            }
            int size = idx.size();
            int [] idxes= new int[size];
            for(i=0;i<size;++i){
                idxes[i]=idx.get(i).intValue();
            }
            SoIndexedLineSet lineSet = new SoIndexedLineSet();
            lineSet.coordIndex.setValues(0,idxes);
            root.addChild(lineSet);
        }
        return root;
    }

    /*
                                        SoSeparator
                                             |
                   |-------------------|----------------|---------------------|
                  SoDrawStyle     SoMaterial      SoCoordinate3       SoIndexedLineSet
     */

    protected static SoNode createLineString3DNode(Geometry geometry,LineString3D polyline3D){
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));
        //material
        {
            List<Color4f> color4fs= null;//polyline3D.getColorList();
            if(color4fs!=null && color4fs.isEmpty()==false) {
                int size = color4fs.size();
                SbColor[] sbColors=new SbColor[size];
                float [] rgba=new float[3];
                for(int i=0;i<size;++i){
                    rgba[0] = color4fs.get(i).getR();
                    rgba[1] = color4fs.get(i).getG();
                    rgba[2] = color4fs.get(i).getB();
                    //rgba[3] = color4fs.get(i).getA();
                    sbColors[i]=new SbColor(rgba);
                }
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.PER_VERTEX_INDEXED);
            }
            else{
                Color4f color4f = geometry.getColor();
                SbColor[] sbColors=new SbColor[1];
                sbColors[0]=new SbColor(color4f.getR(),color4f.getG(),color4f.getB());
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.OVERALL);
            }

        }
        //coordinates
        {
            SoCoordinate3 coordinate3 = new SoCoordinate3();
            int vertexCount = polyline3D.getVertexCount();
            SbVec3d[] vec3ds = new SbVec3d[vertexCount];
            int i = 0;
            for (Vertex3d v : polyline3D.getVertexList()) {
                vec3ds[i] = new SbVec3d(v.getX(), v.getY(), v.getZ());
                ++i;
            }
            coordinate3.point.setValues(0, vec3ds);
            root.addChild(coordinate3);
        }
        {
            //indexes
            int vertexCount = polyline3D.getVertexCount();
            int [] idxes= new int[vertexCount+1];
            int i=0;
            for(i=0;i<vertexCount;++i){
                idxes[i]=i;
            }
            idxes[i]=SO_END_LINE_INDEX;
            SoIndexedLineSet lineSet = new SoIndexedLineSet();
            lineSet.coordIndex.setValues(0,idxes);
            root.addChild(lineSet);
        }
        return root;
    }

    /*
                                                    SoSeparator
                                             |
                   |-------------------|----------------|---------------------|
                  SoDrawStyle     SoMaterial      SoCoordinate3       SoIndexedFaceSet
     */
    protected static SoNode createPolygonalMesh3DNode(Geometry geometry,PolygonalMesh3D polygonalMesh3D){
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));
        //material
        {
            List<Color4f> color4fs= polygonalMesh3D.getColorList();
            if(color4fs!=null && color4fs.isEmpty()==false) {
                int size = color4fs.size();
                SbColor[] sbColors=new SbColor[size];
                float [] rgba=new float[3];
                for(int i=0;i<size;++i){
                    rgba[0] = color4fs.get(i).getR();
                    rgba[1] = color4fs.get(i).getG();
                    rgba[2] = color4fs.get(i).getB();
                    //rgba[3] = color4fs.get(i).getA();
                    sbColors[i]=new SbColor(rgba);
                }
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.PER_VERTEX_INDEXED);
            }
            else{
                Color4f color4f = geometry.getColor();
                SbColor[] sbColors=new SbColor[1];
                sbColors[0]=new SbColor(color4f.getR(),color4f.getG(),color4f.getB());
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.OVERALL);
            }
        }
        //coordinates
        {
            SoCoordinate3 coordinate3 = new SoCoordinate3();
            int vertexCount = polygonalMesh3D.getVertexCount();
            SbVec3d[] vec3ds = new SbVec3d[vertexCount];
            int i = 0;
            List<Vertex3d> vertex3dList = polygonalMesh3D.getVertexList();
            for (Vertex3d v : vertex3dList) {
                vec3ds[i]=new SbVec3d(v.getX(), v.getY(), v.getZ());
                ++i;
            }
            coordinate3.point.setValues(0, vec3ds);
            root.addChild(coordinate3);
        }
        {
            //indexes
            ArrayList<Integer> idx = new ArrayList<>();
            List<Integer> list = polygonalMesh3D.getIndexList();
            int i=0;
            if(list.isEmpty()==false){
                int faceSize  = list.get(i);
                ++i;
                for(int k=0;k<faceSize;++k) {
                    int vertexSize = list.get(i);
                    ++i;
                    for(int j=0;j<vertexSize;++j){
                        idx.add(list.get(i));
                        ++i;
                    }
                    idx.add(SO_END_FACE_INDEX);
                }
            }
            int size = idx.size();
            int [] idxes= new int[size];
            for(i=0;i<size;++i){
                idxes[i]=idx.get(i).intValue();
            }
            SoIndexedFaceSet faceSet = new SoIndexedFaceSet();
            faceSet.coordIndex.setValues(0,idxes);
            root.addChild(faceSet);
        }
        return root;
    }

    /*

                                                    SoSeparator
                                             |
                   |-------------------|----------------|---------------------|
                  SoDrawStyle     SoMaterial      SoCoordinate3       SoIndexedFaceSet

     */
    protected static SoNode createPolyhedralMesh3D(Geometry geometry,PolyhedralMesh3D polyhedralMesh3D){
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));
        //material
        {
            List<Color4f> color4fs= polyhedralMesh3D.getColorList();
            if(color4fs!=null && color4fs.isEmpty()==false) {
                int size = color4fs.size();
                SbColor[] sbColors=new SbColor[size];
                float [] rgba=new float[3];
                for(int i=0;i<size;++i){
                    rgba[0] = color4fs.get(i).getR();
                    rgba[1] = color4fs.get(i).getG();
                    rgba[2] = color4fs.get(i).getB();
                    //rgba[3] = color4fs.get(i).getA();
                    sbColors[i]=new SbColor(rgba);
                }
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.PER_VERTEX_INDEXED);
            }
            else{
                Color4f color4f = geometry.getColor();
                SbColor[] sbColors=new SbColor[1];
                sbColors[0]=new SbColor(color4f.getR(),color4f.getG(),color4f.getB());
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.OVERALL);
            }

        }

        //coordinates
        {
            SoCoordinate3 coordinate3 = new SoCoordinate3();
            int vertexCount = polyhedralMesh3D.getVertexCount();
            SbVec3d [] vec3ds = new SbVec3d[vertexCount];
            int i=0;
            List<Vertex3d> vertex3dList = polyhedralMesh3D.getVertexList();
            for(Vertex3d v : vertex3dList){
                vec3ds[i]=new SbVec3d(v.getX(),v.getY(),v.getZ());
                ++i;
            }
            coordinate3.point.setValues(0,vec3ds);
            root.addChild(coordinate3);
        }

        //indexes
        {
            ArrayList<Integer> idx = new ArrayList<>();
            List<Integer> list = polyhedralMesh3D.getIndexList();
            int i=0;
            if(list.isEmpty()==false){
                int solidSize = list.get(i);
                ++i;
                for(int l=0;l<solidSize;++l){
                    int faceSize  = list.get(i);
                    ++i;
                    for(int k=0;k<faceSize;++k) {
                        int vertexSize = list.get(i);
                        ++i;
                        for(int j=0;j<vertexSize;++j){
                            idx.add(list.get(i));
                            ++i;
                        }
                        idx.add(SO_END_FACE_INDEX);
                    }
                }
            }
            int size = idx.size();
            int [] idxes= new int[size];
            for(i=0;i<size;++i){
                idxes[i]=idx.get(i).intValue();
            }
            SoIndexedFaceSet faceSet = new SoIndexedFaceSet();
            faceSet.coordIndex.setValues(0,idxes);
            root.addChild(faceSet);
        }

        return root;
    }
    /*

                                        SoSeparator
                                             |
                   |-------------------|----------------|---------------------|
                  SoDrawStyle     SoVolumeData      SoTransferFunction   SoVolumeRender
     */
    protected static SoNode createVoxelModelNode(Geometry geometry,VoxelModel voxelModel) {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));


        int c = voxelModel.getVoxelValueCount();
        int capacity = Long.valueOf(voxelModel.getXSize()*voxelModel.getYSize()*voxelModel.getZSize()).intValue()*Double.BYTES;
        ByteBuffer data = ByteBuffer.allocateDirect(capacity);
        data.order(ByteOrder.nativeOrder());
        DoubleBuffer doubleBuffer = data.asDoubleBuffer();
        for (int i = 0; i < c; i++) {
            //data.putDouble(i*Double.BYTES,voxelModel.getVoxelValue(i));
            doubleBuffer.put(i,voxelModel.getVoxelValue(i));
        }

        int dimX = Long.valueOf(voxelModel.getXSize()).intValue();
        int dimY = Long.valueOf(voxelModel.getYSize()).intValue();
        int dimZ = Long.valueOf(voxelModel.getZSize()).intValue();

        // Node to hold the volume data
        // In the first call we specify the voxel dimensions and the actual data.
        // In the second call we specify the 3D extent of the volume in modeling coords.
        SoVolumeData pVolData = new SoVolumeData();
        pVolData.data.setValue(new SbVec3i32(dimX, dimY, dimZ),
                new SbDataType(SbDataType.DataTypes.DOUBLE),data);
        SbBox3f sbBox3f = new SbBox3f(Double.valueOf(voxelModel.getOrigin().getX()).floatValue(),
                Double.valueOf(voxelModel.getOrigin().getY()).floatValue(),
                Double.valueOf(voxelModel.getOrigin().getZ()).floatValue(),
                Double.valueOf(voxelModel.getOrigin().getX()+voxelModel.getXSize()*voxelModel.getXStep()).floatValue(),
                Double.valueOf(voxelModel.getOrigin().getY()+voxelModel.getYSize()*voxelModel.getYStep()).floatValue(),
                Double.valueOf(voxelModel.getOrigin().getZ()+voxelModel.getZSize()*voxelModel.getZStep()).floatValue());
        pVolData.extent.setValue(sbBox3f);

        // Use a predefined colorMap with the SoTransferFunction
        SoTransferFunction pTransFunc = new SoTransferFunction();
        pTransFunc.predefColorMap.setValue(SoTransferFunction.PredefColorMaps.STANDARD);

        // Node in charge of drawing the volume
        SoVolumeRender pVolRender = new SoVolumeRender();
        // Assemble the scene graph
        // Note: SoVolumeRender must appear after the SoVolumeData node.
        root.addChild(pVolData);
        root.addChild(pTransFunc);
        root.addChild(pVolRender);
        return root;
    }


    protected static SoNode createVoxelBlockNode(VolumeModel.DataType voxelDataType, VolumeModel.VoxelBlock voxelBlock) {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(voxelBlock.getBlockInfo().getBlockName());

        long xSize = voxelBlock.getBlockInfo().getXVoxelSize();
        long ySize = voxelBlock.getBlockInfo().getYVoxelSize();
        long zSize = voxelBlock.getBlockInfo().getZVoxelSize();
        double xStep = voxelBlock.getBlockInfo().getXVoxelStep();
        double yStep = voxelBlock.getBlockInfo().getYVoxelStep();
        double zStep = voxelBlock.getBlockInfo().getZVoxelStep();
        Vertex3d origin = voxelBlock.getBlockInfo().getBlockOrigin();


        byte[] byteArray = voxelBlock.getVoxelValue().toByteArray();
        ByteBuffer data = ByteBuffer.wrap(byteArray);
        data.order(ByteOrder.nativeOrder());


        int dimX = Long.valueOf(xSize).intValue();
        int dimY = Long.valueOf(ySize).intValue();
        int dimZ = Long.valueOf(zSize).intValue();

        SbDataType dataType = new SbDataType(SbDataType.DataTypes.DOUBLE);

        switch (voxelDataType) {
            case UNKNOWN:{
                dataType = new SbDataType(SbDataType.DataTypes.UNKNOWN);
                break;
            }
            case INT8: {
                dataType = new SbDataType(SbDataType.DataTypes.SIGNED_BYTE);
                break;
            }
            case INT16: {
                dataType = new SbDataType(SbDataType.DataTypes.SIGNED_SHORT);
                break;
            }
            case INT32: {
                dataType = new SbDataType(SbDataType.DataTypes.SIGNED_INT32);
                break;
            }
            case INT64: {
                dataType = new SbDataType(SbDataType.DataTypes.DOUBLE);
                break;
            }
            case UINT8: {
                dataType = new SbDataType(SbDataType.DataTypes.UNSIGNED_BYTE);
                break;
            }
            case UINT16: {
                dataType = new SbDataType(SbDataType.DataTypes.UNSIGNED_SHORT);
                break;
            }
            case UINT32: {
                dataType = new SbDataType(SbDataType.DataTypes.UNSIGNED_INT32);
                break;
            }
            case UINT64: {
                dataType = new SbDataType(SbDataType.DataTypes.DOUBLE);
                break;
            }
            case FLOAT32: {
                dataType = new SbDataType(SbDataType.DataTypes.FLOAT);
                break;
            }
            case FLOAT64: {
                dataType = new SbDataType(SbDataType.DataTypes.DOUBLE);
                break;
            }
        }

        // Node to hold the volume data
        // In the first call we specify the voxel dimensions and the actual data.
        // In the second call we specify the 3D extent of the volume in modeling coords.
        SoVolumeData pVolData = new SoVolumeData();
        pVolData.data.setValue(new SbVec3i32(dimX, dimY, dimZ),
                dataType,data);
        SbBox3f sbBox3f = new SbBox3f(Double.valueOf(origin.getX()).floatValue(),
                Double.valueOf(origin.getY()).floatValue(),
                Double.valueOf(origin.getZ()).floatValue(),
                Double.valueOf(origin.getX()+xSize*xStep).floatValue(),
                Double.valueOf(origin.getY()+ySize*yStep).floatValue(),
                Double.valueOf(origin.getZ()+zSize*zStep).floatValue());
        pVolData.extent.setValue(sbBox3f);

        // Use a predefined colorMap with the SoTransferFunction
        SoTransferFunction pTransFunc = new SoTransferFunction();
        pTransFunc.predefColorMap.setValue(SoTransferFunction.PredefColorMaps.STANDARD);

        // Node in charge of drawing the volume
        SoVolumeRender pVolRender = new SoVolumeRender();
        // Assemble the scene graph
        // Note: SoVolumeRender must appear after the SoVolumeData node.
        root.addChild(pVolData);
        root.addChild(pTransFunc);
        root.addChild(pVolRender);
        return root;
    }

    protected static SoNode createVoxelVolumeNode(Geometry geometry,VolumeModel vm) {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));
        int count = vm.getBlockCount();
        for(int i=0;i<count;++i){
            SoNode soNode = createVoxelBlockNode(vm.getDataType(),vm.getBlock(i));
            if(soNode!=null)
                root.addChild(soNode);
        }
        return root;
    }
}
